package com.dream.wukong.configcenter.client.remote.http;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dream.wukong.configcenter.client.core.util.ConfigConstant;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.netflix.config.PollResult;
import com.netflix.config.PolledConfigurationSource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.net.URL;
import java.util.List;
import java.util.Map;

/**
* 描  述: rest 风格的 定时轮询获取配置工具类
* 创建时间: 2018/5/23
*/
public class HttpPolledConfigurationSource implements PolledConfigurationSource {

    private static Logger logger = Logger.getLogger(HttpPolledConfigurationSource.class);

    private final List<URL> configUrls;
    private static final String URLSISNULL = "远程获取配置的url地址为空!";


    /**
    * 描  述:
    * 参  数:defaultConfigDirectoryUrl   default 资源的获取url地址
    * 参  数:serviceConfigDirectoryUrl   设置的service 资源的获取url地址
    * 返回值:
    * 创建时间:
    */
    public HttpPolledConfigurationSource(String defaultConfigDirectoryUrl, String serviceConfigDirectoryUrl) {

        if (StringUtils.isBlank(defaultConfigDirectoryUrl)) {
            throw new IllegalArgumentException(URLSISNULL);
        }
        if (StringUtils.isBlank(serviceConfigDirectoryUrl)) {
            throw new IllegalArgumentException(URLSISNULL);
        }
       configUrls = Lists.newArrayListWithCapacity(2);
        try {
            configUrls.add(new URL(defaultConfigDirectoryUrl));
            configUrls.add(new URL(serviceConfigDirectoryUrl));
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }



    /**

    * 描  述: 定时轮询的具体业务逻辑处理方法
    * 参  数:b
    * 参  数:o
    * 返回值: com.netflix.config.PollResult
    * 创建时间: 2018/5/22
    */
    @Override
    public PollResult poll(boolean initial, Object checkPoint) throws Exception {

        if(CollectionUtils.isEmpty(configUrls)){
            return PollResult.createFull(null);
        }
        ////根据父资源节点信息，查询所有子节点列表 并形成url地址返回   （如 default 父节点  得到其下  jdbc  redis 等子节点的获取配置的地址）
        List<String> remoteUrlStrs = HttpSourceConverter.analyzeUrl( configUrls.get(0).toString(), configUrls.get(1).toString());
        if(CollectionUtils.isEmpty(remoteUrlStrs)){
            return PollResult.createFull(null);
        }
        ////将字符串转换成url地址
        List<URL> remoteUrls = createUrls(remoteUrlStrs);
        ////循环获取配置信息
        Map map = pullConfigByRemoteUrls(remoteUrls);
        ////将配置信息交由archaius框架进行处理
        return PollResult.createFull(map);
    }

    /**
    * 描  述:循环获取配置信息
    * 参  数:remoteUrls
    * 返回值: java.util.Map
    * 创建时间: 2018/5/23
    */
    private Map pullConfigByRemoteUrls(List<URL> remoteUrls) {
        Map map = Maps.newHashMap();
        remoteUrls.forEach((URL url) -> {
            ///获取对应返回的json 字符串
            String configString = HttpServer.getInstance().getServerResource(url.toString(), null);
            if (StringUtils.isNotBlank(configString)) {
                JSONArray jsonArrayConfig = new JSONArray();
                try {
                    jsonArrayConfig = JSONArray.parseArray(configString);
                } catch (Exception e) {
                    logger.error("配置值不符合JSONArray格式，配置值：" + configString + "，异常信息:"
                            + e.getLocalizedMessage(), e);
                }
                /////将服务名key 与 json 串value 进行关联 ，service获取的value 会覆盖 default的value (不是整体替换，是具体的配置项替换 比如default jdbc 有 url password属性 service jdbc 有 url user 属性  最终得到default password service url user)
                parseJSONArrayConfig(jsonArrayConfig, url, map);
            }
        });
        return map;
    }


    /***
    * 描  述:  将服务名key 与 json 串value 进行关联
    * 参  数:jsonArrayConfig
    * 参  数:url
    * 参  数:map
    * 返回值: java.util.Map<java.lang.String,com.alibaba.fastjson.JSONObject>
    * 创建时间: 2018/5/23
    */
    public Map<String, JSONObject> parseJSONArrayConfig(JSONArray jsonArrayConfig,
                                                    URL url, Map map) {
        for (int i = 0; i < jsonArrayConfig.size(); ++i) {
            JSONObject json = (JSONObject) jsonArrayConfig.get(i);
            String sourceName =  ConfigConstant.getServiceName(url.toString(),configUrls.get(0).toString(),configUrls.get(1).toString());
            ///////中和defaul 与service 的配置
            if(map.containsKey(sourceName)){
                JSONObject newJson = new JSONObject();
                JSONObject oldJson = (JSONObject) map.get(sourceName);
                for (String oldKey : oldJson.keySet()) {
                    newJson.put(oldKey, oldJson.get(oldKey));
                }
                for (String key : json.keySet()) {
                    newJson.put(key, json.get(key));
                }
                json = newJson;
            }
            map.put(sourceName, json);
        }
        return map;
    }

    /**
    * 描  述:  根据url地址返回对应的URL对象集合 ，主要效验url格式
    * 参  数:urlStrings
    * 返回值: java.util.List<java.net.URL>
    * 创建时间: 2018/5/22
    */
    private static List<URL> createUrls(List<String> urlStrings) {
        if(CollectionUtils.isEmpty(urlStrings)){
            throw new IllegalArgumentException(URLSISNULL);
        }
        List<URL> urls = Lists.newArrayList();
        urlStrings.forEach(url -> {
            try {
                urls.add(new URL(url));
            }catch (Exception e){
                throw new RuntimeException(e);
            }
        });
        return urls;
    }
}
